package com.wushijia.java8.lambda;

import com.wushijia.model.Quote;
import com.wushijia.model.Shop;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

public class CompletableFutureDemo2 {

  public static void main(String[] args) {
    List<Shop> shopList = Arrays.asList(new Shop("BestPrice"),
        new Shop("LetSaveBig"),
        new Shop("MyFavoriteShop"),
        new Shop("BuyItAll"));

    //定制执行器
    final Executor executor = Executors.newFixedThreadPool(Math.min(shopList.size(), 100), new ThreadFactory() {
      @Override
      public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
      }
    });

    long start2 = System.nanoTime();
    //System.out.println(findPriceByExecutor(shopList, "myPhone", executor));
    printPriceByExecutor(shopList, "myPhone", executor);
    long duration = (System.nanoTime() - start2) / 1_000_000;
    System.out.println("Done in " + duration + " msecs");

  }

  public static List<String> findPrice(List<Shop> shops, String productName) {
    return shops.stream().map(shop -> shop.getPrice(productName)).map(Quote::parse).map(Discount::applyDiscount).collect(toList());
  }

  private static List<String> findPriceByExecutor(List<Shop> shops, String productName, Executor executor) {
    List<CompletableFuture<String>> priceFuture = shops.stream()
        .map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(productName), executor))
        //Quote对象存在时，对其返回值进行转换，thenApply会在COmpletableFuture完成执行后使用它的返回值
        .map(future -> future.thenApply(Quote::parse))
        //使用另一个异步任务构造期望的Future,申请折扣
        .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor))).collect(toList());
    return priceFuture.stream().map(CompletableFuture::join).collect(toList());
  }

  private static void printPriceByExecutor(List<Shop> shops, String productName, Executor executor) {
    long start = System.nanoTime();
    Stream<CompletableFuture<String>> priceFuture = shops.stream()
        .map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(productName), executor))
        //Quote对象存在时，对其返回值进行转换，thenApply会在COmpletableFuture完成执行后使用它的返回值
        .map(future -> future.thenApply(Quote::parse))
        //使用另一个异步任务构造期望的Future,申请折扣
        .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)));

    //priceFuture.map(f -> f.thenAccept(s -> System.out.println(s)));//返回的是Stream<CompletableFuture<Void>>对象，只能等待其结束

    /*CompletableFuture[] futures = priceFuture
        .map(f -> f.thenAccept(s -> System.out.println(s + " done in " + (System.nanoTime() - start) / 1_000_000 + " msecs")))
        .toArray(size -> new CompletableFuture[size]);*/

    /*CompletableFuture[] futures = priceFuture
        .map(f -> f.thenAccept(System.out::println))
        .toArray(size -> new CompletableFuture[size]);*/

    //数组中所有CompletableFuture对象执行完成
    //CompletableFuture.allOf(futures).join();

    //数组中任一CompletableFuture对象执行完成,返回一个CompletableFuture<Object>
    //CompletableFuture.anyOf(futures).join();

  }
}
